import osm_utils4
import wayzUtils
import time
from osm_utils4 import *
import matplotlib.pyplot as plt
import numpy as np
import csv
import SolutionToSpeedUpdates
class test():
    def __init__(self,agent = None):
        self.map = CountryMap()
        self.map.LoadMap2()
        self.lastTestDuration = 0       
        self.weight = 0.7 
        self.limit = 999999
        self.problems = []
        self.results = {}
        self.resultsAstarCompare = {}
        self.agent = agent
        self.weightResults = {}
        for i in range(6):
            self.results[i] = []
        for i in range(12):
            self.resultsAstarCompare[i] = []
        for i in range(4):
            self.weightResults[i] = []
        
    def singleTest(self,source,target,distRate,speedRate,efficRate,weighted = False, carProfile = DEFAULT_CAR):
        isCombined = (distRate*speedRate != 0.0 or distRate*efficRate != 0.0 or efficRate*speedRate != 0.0)
        state = wayzUtils.SolutionProblemState(source,target,self.map,distRate,speedRate,efficRate,carProfile, isCombined)        
        print "-------------------------------------"
        print "source junction %d" % (source)
        print "target junction %d" % (target)
        print "aerial distance is ", (self.map.JunctionDistance(source, target))
        print "isCombined = ",isCombined
#        osm_utils4.openCount = 0
        if weighted:
            agent = wayzUtils.WayzWeightedProblemAgent()
            beginTime = time.clock()
            self.lastSolved = agent.solve(state,self.weight,self.limit)
            print "weight = ",self.weight
        else:
            if self.agent == None:
                agent = wayzUtils.WayzProblemAgent()
            else:
                agent = self.agent
            beginTime = time.clock()
            self.lastSolved = agent.solve(state,self.limit)
        self.lastTestDuration = time.clock() - beginTime
        self.lastSource = source
        self.lastTarget = target
#        print "opened nodes ", osm_utils4.openCount
        if (self.lastSolved != None) :
            totalCost = 0.0
            totalDist = 0.0
            totalTime = 0.0
            for action in self.lastSolved:
                totalCost = totalCost + action.cost
                totalDist = totalDist + action.dist
                totalTime = totalTime + action.dist/action.speed
            print "total cost is ", (totalCost)
            print "total distance is ", (totalDist)
            print "total time is ", (totalTime)
        else:
            print "found nothing "
            print "algo duration ", (self.lastTestDuration)
            return [source,target,-1,0,0,0,0]
        print "algo duration ", (self.lastTestDuration)
        print "num of junctions is ", len(self.lastSolved)
        testSummery = [source,target,totalCost,self.lastTestDuration,len(self.lastSolved),totalDist, totalTime]
        return testSummery
            
    def generateAndTest(self,distRate,speedRate,efficRate):
        problemKeys = self.map.GenerateProblem()
        self.singleTest(problemKeys[0],problemKeys[1],distRate,speedRate,efficRate)
        
    def repeatTest(self,distRate,speedRate,efficRate):
        self.singleTest(self.lastSource,self.lastTarget,distRate,speedRate,efficRate)
       
    def lengthMinimizationTest(self):
        self.singleTest(self.lastSource,self.lastTarget,1,0,0)
    
    def timeMinimizationTest(self):
        self.singleTest(self.lastSource,self.lastTarget,0,1,0)
    
    def consumptionMinimizationTest(self):
        return self.singleTest(self.lastSource,self.lastTarget,0,0,1)
    
    def generateProblem(self):
        problemKeys = self.map.GenerateProblem()
        self.lastSource = problemKeys[0]
        self.lastTarget = problemKeys[1]
        
    def generateProblems(self, num):
        print "generating problems"
        for i in range(num):
            self.problems.insert(i,self.map.GenerateProblem())
#            self.problems.insert(i,[918327,572887])
        print "problems generated"
         
    def minimizeTrack(self,source,target,weighted = False):
        return self.singleTest(source,target,1,0,0,weighted)
        
    def minimizeTime(self,source,target,weighted = False,carProfile = 'Peugeot 508'):
        return self.singleTest(source,target,0,1,0,weighted,carProfile)
   
    def minimizeGas(self,source,target,weighted = False,carProfile = 'Peugeot 508'):
        return self.singleTest(source,target,0,0,1,weighted,carProfile)
       
    def minimizeRates(self,source,target,distRate,speedRate,efficRate,weighted = False,carProfile = 'Peugeot 508'):
        return self.singleTest(source,target,distRate,speedRate,efficRate,weighted,carProfile)
        
    def hundredProblemsExec(self, num):
        with open('resultsTable.csv', 'wb') as csvfile:
            resWriter = csv.writer(csvfile, delimiter=',',
                            quotechar='|', quoting=csv.QUOTE_MINIMAL)
            resWriter.writerow(['source','target','path cost','cpu time','num of path nodes','distance (km)','time (h)'])
            for i in range(num):
                print str(i)
                tmpProblem = self.map.GenerateProblem()
                tmpSolved = self.minimizeTrack(tmpProblem[0],tmpProblem[1])
                while tmpSolved[2] == -1:
                    tmpProblem = self.map.GenerateProblem()
                    tmpSolved = self.minimizeTrack(tmpProblem[0],tmpProblem[1])
                    
                self.problems.insert(i,tmpProblem)
                self.results[0].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "q1"
                tmpSolved = self.minimizeTime(self.problems[i][0],self.problems[i][1])             
                self.results[1].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "q2"
                tmpSolved = self.minimizeGas(self.problems[i][0],self.problems[i][1])
                self.results[2].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "q3"
                tmpSolved = self.minimizeGas(self.problems[i][0],self.problems[i][1],False,'Skoda Fabia')
                self.results[3].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "q4"
                tmpSolved = self.singleTest(self.problems[i][0],self.problems[i][1],0.1,0.4,0.5,False,'Peugeot 508')
                self.results[4].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "q5"
                tmpSolved = self.singleTest(self.problems[i][0],self.problems[i][1],0.3,0.4,0.3,False,'Skoda Fabia')
                self.results[5].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "q6" 
                self.problems.insert(i,self.map.GenerateProblem())
            print self.results
#            self.makeAndExportDurationGraph(num)
#            self.makeAndExportDistanceGraph(num)
#            self.makeAndExportTimeeGraph(num)
        
    def makeAndExportDurationGraph(self,num):
        durations = []
        prev = 0
        maximum = 0
        for i in range(6):
            durations.append([])
        for i in range(num):
            for j in range(6):
                if len(durations[j]) > 0:
                    prev = durations[j][-1]
                if self.results[j][i][3] == 0:
                    durations[j].append(prev)
                else:
                    durations[j].append(self.results[j][i][3])
                if maximum < self.results[j][i][3]:
                    maximum = self.results[j][i][3]
        
        plt.plot(range(num),durations[0], '-b',label ='min distance')
        plt.plot(range(num),durations[1], '-r',label = 'min time')
        plt.plot(range(num),durations[2], '-y',label = 'min gas peugeot')
        plt.plot(range(num),durations[3], '-m',label = 'min gas mazda')
        plt.plot(range(num),durations[4], '-c',label = 'min combined (0.1,0.4,0.5) peugeot')
        plt.plot(range(num),durations[5], '-g',label = 'min combined (0.3,0.4,0.3) mazda')
        plt.axis([0,num,0,(maximum*1.25)])
        plt.xlabel('run number')
        plt.ylabel('run time')
        plt.legend(prop={'size':8})
        plt.title('comparing algorithm duration')
        plt.savefig('results')
        plt.close()
        
            
    def makeAndExportDistanceGraph(self,num):
        distance = []
        prev = 0
        maximum = 0
        for i in range(6):
            distance.append([])
        for i in range(num):
            for j in range(6):
                if len(distance[j]) > 0:
                    prev = distance[j][-1]  #get last value
                if self.results[j][i][5] == 0:
                    distance[j].append(prev)
                else:
                    distance[j].append(self.results[j][i][5])
                if maximum < self.results[j][i][5]:
                    maximum = self.results[j][i][5]
        
        plt.plot(range(num),distance[0], '-b',label ='min distance')
        plt.plot(range(num),distance[1], '-r',label = 'min time')
        plt.plot(range(num),distance[2], '-y',label = 'min gas peugeot')
        plt.plot(range(num),distance[3], '-m',label = 'min gas mazda')
        plt.plot(range(num),distance[4], '-c',label = 'min combined (0.1,0.4,0.5) peugeot')
        plt.plot(range(num),distance[5], '-g',label = 'min combined (0.3,0.4,0.3) mazda')
        plt.axis([0,num,0,(maximum*1.25)])
        plt.xlabel('run number')
        plt.ylabel('total distance')
        plt.legend(prop={'size':8})
        plt.title('comparing algorithm path distance results')
        plt.savefig('distances')
        plt.close()
                    
    def makeAndExportTimeeGraph(self,num):
        time = []
        prev = 0
        maximum = 0
        for i in range(6):
            time.append([])
        for i in range(num):
            for j in range(6):
                if len(time[j]) > 0:
                    prev = time[j][-1]  #get last value
                if self.results[j][i][6] == 0:
                    time[j].append(prev)
                else:
                    time[j].append(self.results[j][i][6])
                if maximum < self.results[j][i][6]:
                    maximum = self.results[j][i][6]
        
        plt.plot(range(num),time[0], '-b',label = 'min distance')
        plt.plot(range(num),time[1], '-r',label = 'min time')
        plt.plot(range(num),time[2], '-y',label = 'min gas peugeot')
        plt.plot(range(num),time[3], '-m',label = 'min gas mazda')
        plt.plot(range(num),time[4], '-c',label = 'min combined (0.1,0.4,0.5) peugeot')
        plt.plot(range(num),time[5], '-g',label = 'min combined (0.3,0.4,0.3) mazda')
        plt.axis([0,num,0,(maximum*1.25)])
        plt.xlabel('run number')
        plt.ylabel('total time')
        plt.legend(prop={'size':8})
        plt.title('comparing algorithm path time results')
        plt.savefig('times')
        plt.close()
        
    def hundredProblemsWeightExec(self, num, weight):
        fileName = 'weightResultsTable'+str(weight)+'.csv'
        with open(fileName, 'wb') as csvfile:
            resWeightWriter = csv.writer(csvfile, delimiter=',',
                            quotechar='|', quoting=csv.QUOTE_MINIMAL)
            resWeightWriter.writerow(['source','target','path cost','cpu time','num of path nodes','distance (km)','time (h)'])
            self.weight = weight
            for j in range(4):
                self.weightResults[j] = []
                
            numOfProblems = len(self.problems)
            print 'num of problems ',numOfProblems
            for i in range(num):
                tmpSolved = self.minimizeTrack(self.problems[i][0],self.problems[i][1],True)
                self.weightResults[0].append(tmpSolved)
                resWeightWriter.writerow(tmpSolved)
                print "qweight1"
                tmpSolved = self.minimizeTime(self.problems[i][0],self.problems[i][1],True)
                self.weightResults[1].append(tmpSolved)
                resWeightWriter.writerow(tmpSolved)
                print "qweight2"
                tmpSolved = self.minimizeGas(self.problems[i][0],self.problems[i][1],True)
                self.weightResults[2].append(tmpSolved)
                resWeightWriter.writerow(tmpSolved)
                print "qweight3"
                tmpSolved = self.singleTest(self.problems[i][0],self.problems[i][1],0.2,0.3,0.5,True,'Peugeot 508')
                self.weightResults[3].append(tmpSolved)
                resWeightWriter.writerow(tmpSolved)
                print "qweight4"
            print self.weightResults
        
    def hundredProblemsWeightGenExec(self, num, weight):
        fileName = 'weightResultsTable'+str(weight)+'.csv'
        with open(fileName, 'wb') as csvfile:
            resWeightWriter = csv.writer(csvfile, delimiter=',',
                            quotechar='|', quoting=csv.QUOTE_MINIMAL)
            resWeightWriter.writerow(['source','target','path cost','cpu time','num of path nodes','distance (km)','time (h)'])
            self.weight = weight
            for j in range(4):
                self.weightResults[j] = []
            
            for i in range(num):
                print str(i)
                tmpProblem = self.map.GenerateProblem()
                self.problems.insert(i,tmpProblem)   
                tmpSolved = self.minimizeTrack(self.problems[i][0],self.problems[i][1],True)
                while tmpSolved[2] == -1:
                    tmpProblem = self.map.GenerateProblem()
                    tmpSolved = self.minimizeTrack(tmpProblem[0],tmpProblem[1],True)
                    self.problems.insert(i,tmpProblem)  
                self.weightResults[0].append(tmpSolved)
                resWeightWriter.writerow(tmpSolved)
                print "qweight1"
                tmpSolved = self.minimizeTime(tmpProblem[0],tmpProblem[1],True)
                self.weightResults[1].append(tmpSolved)
                resWeightWriter.writerow(tmpSolved)
                print "qweight2"
                tmpSolved = self.minimizeGas(tmpProblem[0],tmpProblem[1],True)
                self.weightResults[2].append(tmpSolved)
                resWeightWriter.writerow(tmpSolved)
                print "qweight3"
                tmpSolved = self.singleTest(tmpProblem[0],tmpProblem[1],0.2,0.3,0.5,True,'Peugeot 508')
                self.weightResults[3].append(tmpSolved)
                resWeightWriter.writerow(tmpSolved)
                print "qweight4"
            print self.weightResults
            print 'problems ', self.problems
            
    def makeAndExportWeightGraph(self,num):
        durations = []
        prev = 0
        maximum = 0
        for i in range(4):
            durations.append([])
        for i in range(num):
            for j in range(4):
                if len(durations[j]) > 0:
                    prev = durations[j][-1]  #get last value
                if self.weightResults[j][i][3] == 0:
                    durations[j].append(prev)
                else:
                    durations[j].append(self.weightResults[j][i][3])
                if maximum < self.weightResults[j][i][3]:
                    maximum = self.weightResults[j][i][3]
                
        plt.plot(range(num),durations[0], '-b',label = 'min distance')
        plt.plot(range(num),durations[1], '-r',label ='min time')
        plt.plot(range(num),durations[2], '-y',label ='min gas')
        plt.plot(range(num),durations[3], '-m',label ='min combined')
        plt.axis([0,num,0,(maximum*1.25)])
        plt.legend(prop={'size':8})
        plt.xlabel('run number')
        plt.ylabel('run time')
        plt.title('comparing weighted algorithm duration')
        plt.savefig('weighted results '+str(self.weight)+'.png')
        plt.close()
    def AstarCompare(self, num):
        with open('AstarCompare.csv', 'wb') as csvfile:
            resWriter = csv.writer(csvfile, delimiter=',',
                            quotechar='|', quoting=csv.QUOTE_MINIMAL)
            for i in range(num):
                print str(i)
                self.agent = None
                tmpProblem = self.map.GenerateProblem()
                tmpSolved = self.minimizeTrack(tmpProblem[0],tmpProblem[1])
                while tmpSolved[2] == -1 or tmpSolved[2]>40:
                    tmpProblem = self.map.GenerateProblem()
                    tmpSolved = self.minimizeTrack(tmpProblem[0],tmpProblem[1])
                    
                self.problems.insert(i,tmpProblem)
                self.resultsAstarCompare[0].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Length Before"
                self.agent = SolutionToSpeedUpdates.WayzProblemAgentUpdatesAStar()
                tmpSolved = self.minimizeTrack(self.problems[i][0],self.problems[i][1])             
                self.resultsAstarCompare[1].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Length Improved"
                self.agent = SolutionToSpeedUpdates.WayzProblemAgentUpdatesAStarNaive()
                tmpSolved = self.minimizeTrack(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[2].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Length Naive"
                self.agent = None
                tmpSolved = self.minimizeTrack(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[3].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Length After"
                self.agent = None
                tmpSolved = self.minimizeGas(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[4].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Consumption Before"
                self.agent = SolutionToSpeedUpdates.WayzProblemAgentUpdatesAStar()
                tmpSolved = self.minimizeGas(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[5].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Consumption Improved" 
                self.agent = SolutionToSpeedUpdates.WayzProblemAgentUpdatesAStarNaive()
                tmpSolved = self.minimizeGas(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[6].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Consumption Naive" 
                self.agent = None
                tmpSolved = self.minimizeGas(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[7].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Consumption After"
                self.agent = None
                tmpSolved = self.minimizeTime(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[8].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Time Before"
                self.agent = SolutionToSpeedUpdates.WayzProblemAgentUpdatesAStar()
                tmpSolved = self.minimizeTime(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[9].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Time Improved" 
                self.agent = SolutionToSpeedUpdates.WayzProblemAgentUpdatesAStarNaive()
                tmpSolved = self.minimizeTime(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[10].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Time Naive" 
                self.agent = None
                tmpSolved = self.minimizeTime(self.problems[i][0],self.problems[i][1])
                self.resultsAstarCompare[11].append(tmpSolved)
                resWriter.writerow(tmpSolved)
                print "Time After"
                
                self.problems.insert(i,self.map.GenerateProblem())
            print self.resultsAstarCompare
#            self.makeAndExportDurationGraph(num)
#            self.makeAndExportDistanceGraph(num)
#            self.makeAndExportTimeeGraph(num)